﻿namespace DeltaGroup.WheelOfJeopardy.UI.Screens
{
    using System;
    using System.Collections.Generic;
    using System.Windows.Controls;

    using DeltaGroup.WheelOfJeopardy.Model;
    using DeltaGroup.WheelOfJeopardy.UI.Events;
    using DeltaGroup.WheelOfJeopardy.UI.ViewModel;
    using DeltaGroup.WheelOfJeopardy.Util;

    /// <summary>
    ///     Interaction logic for WheelController.xaml
    /// </summary>
    public partial class WheelScreen : UserControl
    {
        #region Fields

        private readonly List<SectorInfo> sectorInfos;

        #endregion Fields

        #region Constructors

        /// <summary>
        ///     Initializes a new instance of the <see cref = "WheelController" /> class.
        /// </summary>
        public WheelScreen()
        {
            InitializeComponent();
        }

        /// <summary>
        ///     Initializes a new instance of the <see cref = "WheelScreen" /> class.
        /// </summary>
        /// <param name = "sectors">The sectors.</param>
        public WheelScreen(List<string> categories)
            : this()
        {
            sectorInfos = CreateSectorInfos(categories);

            wheelControl.LayoutSectors(sectorInfos);
        }

        #endregion Constructors

        #region Events

        /// <summary>
        /// Occurs when [sector selected].
        /// </summary>
        public event EventHandler<SectorSelectedEventArgs> SectorSelected;

        #endregion Events

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether [debug mode].
        /// </summary>
        /// <value><c>true</c> if [debug mode]; otherwise, <c>false</c>.</value>
        public bool DebugMode
        {
            get { return wheelControl.DebugMode; }
            set { wheelControl.DebugMode = value; }
        }

        /// <summary>
        ///     Gets the current sector count.
        /// </summary>
        /// <value>The current sector count.</value>
        private int CurrentSectorCount
        {
            get { return sectorInfos.Count; }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        ///     Displays the wheel.
        /// </summary>
        public void Reset()
        {
            meterControl.ResetMeter();
            wheelControl.PrepareForSpin();
        }

        /// <summary>
        /// Creates the category sectors.
        /// </summary>
        /// <param name="categories">The categories.</param>
        /// <returns></returns>
        private static List<SectorInfo> CreateCategorySectors(List<string> categories)
        {
            List<SectorInfo> sectors = new List<SectorInfo>();
            for (int cat = 0; cat < categories.Count; cat++)
            {
                for (int instance = 0; instance < 3; instance++)
                {
                    sectors.Add(new SectorInfo(new CategorySector(categories[cat]), cat.ToString()));
                }
            }

            return sectors.Shuffle();
        }

        /// <summary>
        /// Creates the sector infos.
        /// </summary>
        /// <param name="categories">The categories.</param>
        /// <returns></returns>
        private static List<SectorInfo> CreateSectorInfos(List<string> categories)
        {
            List<SectorInfo> sectors = new List<SectorInfo>();

            sectors.AddRange(CreateCategorySectors(categories));
            sectors.AddRange(CreateSpecialSectors());

            return sectors.Shuffle();
        }

        /// <summary>
        /// Creates the special sectors.
        /// </summary>
        /// <returns></returns>
        private static List<SectorInfo> CreateSpecialSectors()
        {
            List<SectorInfo> sectors = new List<SectorInfo>();

            sectors.Add(new SectorInfo(new BankruptSector()));         
            sectors.Add(new SectorInfo(new FreeTurnSector()));         
            sectors.Add(new SectorInfo(new LoseTurnSector()));         
            sectors.Add(new SectorInfo(new OpponentsChoiceSector()));  
            sectors.Add(new SectorInfo(new PlayersChoiceSector()));    
            sectors.Add(new SectorInfo(new SpinAgainSector()));        

            return sectors;
        }

        /// <summary>
        ///     Gets the degrees in sector.
        /// </summary>
        /// <returns></returns>
        private double GetDegreesInSector()
        {
            return WheelMathUtil.CalculateWheelSectorDegrees(CurrentSectorCount);
        }

        /// <summary>
        ///     Handles the PowerLevelCaptured event of the meterControl control.
        /// </summary>
        /// <param name = "sender">The source of the event.</param>
        /// <param name = "e">The <see cref = "DeltaGroup.WheelOfJeopardy.WheelManager.UI.PowerLevelEventArgs" /> instance containing the event data.</param>
        private void meterControl_PowerLevelCaptured(object sender, PowerLevelEventArgs e)
        {
            wheelControl.SpinWheel(ScaleRotationValue(e.PowerLevel));
        }

        /// <summary>
        ///     Raises the spin completed event.
        /// </summary>
        private void RaiseSpinCompletedEvent(SectorSelectedEventArgs e)
        {
            if (SectorSelected != null)
            {
                SectorSelected(this, e);
            }
        }

        /// <summary>
        ///     Scales the rotation value.
        /// </summary>
        /// <param name = "powerLevel">The power level.</param>
        /// <returns></returns>
        private double ScaleRotationValue(double powerLevel)
        {
            // Power level at 100 will rotate 377DEG * 2.75
            return (powerLevel * 3.77d) * 2.75d;
        }

        /// <summary>
        ///     Handles the SpinCompleted event of the wheelControl control.
        /// </summary>
        /// <param name = "sender">The source of the event.</param>
        /// <param name = "e">The <see cref = "DeltaGroup.WheelOfJeopardy.WheelManager.UI.SpinCompleteEventArgs" /> instance containing the event data.</param>
        private void wheelControl_SpinCompleted(object sender, SectorSelectedEventArgs e)
        {
            RaiseSpinCompletedEvent(e);
        }

        #endregion Methods
    }
}